#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <mutex>

const int defaultCap = 10;

template <typename T>
class cqueue
{
private:
    int _cap;
    std::vector<T> _rq;
    int _p_pos;
    int _c_pos;
    sem_t _blank;
    sem_t _data;
    std::mutex _p_mtx;
    std::mutex _c_mtx;

public:
    // base func
    cqueue(int cap = defaultCap);
    ~cqueue();
    // feature func
    void put(T data);
    T get();
};

template <typename T>
inline cqueue<T>::cqueue(int cap)
    : _cap(cap), _rq(_cap), _p_pos(0), _c_pos(0)
{
    sem_init(&_blank, 0, _cap);
    sem_init(&_data, 0, 0);
}

template <typename T>
inline cqueue<T>::~cqueue()
{
    sem_destroy(&_blank);
    sem_destroy(&_data);
}

template <typename T>
inline void cqueue<T>::put(T data)
{
    sem_wait(&_blank);
    {
        std::lock_guard<std::mutex> lock(_p_mtx);
        _rq[_p_pos] = data;
        _p_pos = (_p_pos + 1) % _cap;
    }
    sem_post(&_data);
}

template <typename T>
inline T cqueue<T>::get()
{
    T ret;
    sem_wait(&_data);
    {
        std::lock_guard<std::mutex> lock(_c_mtx);
        ret = _rq[_c_pos];
        _c_pos = (_c_pos + 1) % _cap;
    }
    sem_post(&_blank);
    return ret;
}
